home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-18 | 60.1 KB | 2,089 lines |
- ; common routines between 3d1.asm,3d2.asm and 3d3.asm
-
- public poly_fill ; fill polygon
- public clear_fill ; clear screen
- public initpages ; initialize video pages selected
- public flip_page ; flip between video pages
- public fakeline ; draw line in memory buffer
- public set_clip_absolute ; set clipping parameters - absolute
- public set_clip_offset ; set clipping parameters - offset
- public updvectors ; update vector positions/angles
- public fastimultable ; fast imul table, dw 0-319 * 200
- public clipped_line ; draw clipped line from dx,cx to ax,bx colour bp
- public sort_list ; sort vector list
- public drawvect ; draw vectors from command list
- public look_at_it ; force camera to look at object
- public calc_angles ; calculate angles between objects di,si
- public calc_middle ; calculate angles of ebx,ecx,ebp into x,y
- public get_displacement ; calculate difference between objects
- public put_object ; put object si at ebx,ecx,ebp
- public set_angle ; set object si to angle ebx,ecx,ebp
- public set_shape ; set shape of object si to ax
- public set_object_on ; set object si to on
- public set_object_off ; guess...
- public resetupd ; reset clearing limits (for clear_fill)
- public move_si ; move object si to ebx,ecx,ebp in di
- public twist_si ; rotate object si to ebx,ecx,ebp in di
- public newfollow ; select new object for camera to follow
- public where_si ; where will object si be in di frames?
- public set_finall ; set xsfinal for object (location)
- public set_finala ; set vxsfinal for object (angles)
- public point_it ; point object si at object di
- public point_dir ; point object si in direction it is moving
- public point_to ; point object si at location ebx,ecx,ebp
- public set_speed ; calculate velocity based on angles
- public point_time ; point obj di to bx,cx,bp in di frames
- public nullpalette ; only a null cross reference palette
- public set_xref_palette ; set cross reference pal for object si to ebx
-
- ; clears a block from active display page
- ;
- ; this routine works only if borders of xclip land on even nybbles
- ; eg minimum x is 32 - works fine. but if minimum x is 37, this
- ; routine will clear all the way to 32 just the same. for better clearing,
- ; call fill_block routine with lxupdate and lyupdate parameters on stack
- ;
- ; routine was originally written by matt prichard. routine was then modified
- ; to clear using dwords, and clear to integer borders.
- ;
- ; entry: lxupdate+0 = left x position of area to fill
- ; lxupdate+2 = top y position of area to fill
- ; lyupdate+0 = right x position of area to fill
- ; lyupdate+2 = bottom y position of area to fill
-
- align 16
-
- clear_fill:
- cmp use_clear,no
- je tf_exit ; don't use clear routine
-
- mov edi, current_page ; point to active vga page
-
- ; out_8 sc_index, map_mask ; set up for plane select, should be already set
- out_8 sc_data, all_planes ; write to all planes
-
- if usefastborders eq no
- if useborders eq yes
- cld ; direction flag = forward
-
- mov ax,lxupdate+0
- mov bx,lxupdate+2
- mov cx,lyupdate+0
- mov dx,lyupdate+2
-
- add ax,xcent ; center on screen
- add bx,xcent
- add cx,ycents1
- add dx,ycentp1
-
- and ax,0fff8h
- and bx,0fff8h
- add bx,7
-
- cmp ax,cliplt ; clip to inside borders
- jge s tf_noclip1
- mov ax,cliplt
- tf_noclip1:
- cmp bx,xmaxxcent
- jl s tf_noclip2
- mov bx,cliprt
- tf_noclip2:
- cmp cx,cliptp
- jge s tf_noclip3
- mov cx,cliptp
- tf_noclip3:
- cmp dx,ymaxycent
- jl s tf_noclip4
- mov dx,ymaxycent
- tf_noclip4:
- mov lxupdate+0,ax
- mov lxupdate+2,bx
- mov lyupdate+0,cx
- mov lyupdate+2,dx
-
- cmp ax,bx
- jg tf_exit ; nothing to do!
-
- cmp cx,dx
- jg tf_exit ; nothing to do!
-
- mov ax,cx
- mov bx,dx
-
- sub bx,ax ; get y width
- mov lyupdate+2,bx ; save in ypos2
-
- else ; if not using borders update, clear entire
- mov ax,cliptp ; area!
- mov bx,ymaxycent
- mov cx,cliplt ; use this if you want to change the
- mov lxupdate+0,cx ; clipping paramters while the program is
- mov cx,cliprt ; running, and if you want to have useborders
- mov lxupdate+2,cx ; = no. the alternative code to this is the
- mov dx,bx ; rept code below. it is faster but takes
- sub dx,ax ; more memory.
- mov lyupdate+2,dx
-
- endif
-
- movzx esi,ax
- movzx eax,w [esi*2+fastimultable] ; mul y1 by bytes per line
- add edi,eax ; di = start of line y1
-
- mov dx,lxupdate ; dx = x1 (pixel position)
- shr dx,2 ; dx/4 = bytes into line
- movzx edx,dx
- add edi,edx ; di = addr of upper-left corner
-
- mov cx,lxupdate+2 ; cx = x2 (pixel position)
- sub cx,lxupdate
- shr cx,3 ; cx/4 = bytes into line
- inc cx
-
- ; di = addr of upper left block to fill
- ; cx = # of bands to fill in (width)
-
- mov dx,xactual/4 ; dx = di increment
- sub dx,cx ; = screen_width-# planes filled
- sub dx,cx
-
- movzx ecx,cx
- mov ebx,ecx ; bx = quick refill for cx
- mov si,lyupdate+2 ; si = # of lines to fill
- mov ax,background ; get fill color
- push ax ; make 32 bit
- shl eax,16
- pop ax
-
- shr ecx,1
- shr ebx,1
- jnc s tf_middle_loop2
-
- align 4
-
- tf_middle_loop1:
- stosw
- rep stosd ; fill in entire line
-
- mov ecx, ebx ; recharge cx (line width)
- add edi, edx ; point to start of next line
- loopx si, tf_middle_loop1 ; loop until all lines drawn
-
- ret
-
- align 16
-
- tf_middle_loop2:
- rep stosd ; fill in entire line, doubleword store
-
- mov ecx, ebx ; recharge cx (line width)
- add edi, edx ; point to start of next line
- loopx si, tf_middle_loop2 ; loop until all lines drawn
- tf_exit:
- ret ; exit
-
- ; this rept code generates a huge program that wipes the screen FAST
- ; only use this if you don't want to change the clipping parameters while
- ; the program is running.
-
- else ; if useborders = no, clear entire area
-
- mov ax,background ; get fill color
- shl eax,16 ; make 32 bit
- mov ax,background
-
- i=0 ; this is a huge but fast method
- rept (ymax-ymin)
- j=0
- rept (xmax-xmin)/4/4
-
- mov d [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],eax
-
- j=j+4
- endm
-
- if (xmax-xmin)/4/4 ne (xmax+8-xmin)/4/4
- mov w [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],ax
- endif
-
- i=i+1
- endm
- tf_exit:
- ret
-
- endif
-
- ; fill starting at oney, from firstbyte to lastbyte
-
- align 16
- pf_done:
- pop eax
- pf_outearly:
- mov oney,1000 ; reset for next polygon call
- ret
-
- align 16
- poly_fill:
-
- ; out_8 sc_index, map_mask ; set up for plane select
-
- xor eax,eax
- mov bx,oney ; ax=y1
- cmp bx,ymins
- jl s pf_missub
-
- cmp bx,ymaxs
- jge pf_outearly
- sub bx,ymins
- mov ax,bx
- pf_missub:
- if usesteel eq yes
- cmp steel,0 ; test to use steel texture
- jl s pf_skipsteel
- mov bl,colq ; yes, save colour offset and 16 block
- mov steelc,bl
- and steelc,0f0h ; save base offset of 16 colour block
- shl bl,2 ; colour offset is *2 (small) *4 (large)
- add bl,al ; make steel always constant
- and bl,03fh ; colour indexer (so sides look different)
- mov steel ,bl
- pf_skipsteel:
- endif
-
- mov ebp,eax ; indexer to line
- shl bp,1
- add ax, cliptp
-
- mov edi, current_page ; point to active vga page
- mov esi,eax
- mov ax,w [esi*2+fastimultable] ; mul y1 by bytes per line
-
- add edi,eax ; di = start of line y1
- xor edx,edx
-
- pf_more_lines:
- push edi ; save right hand position
- mov ax, [firstbyte+ebp]
- cmp ax,xmaxs ; check if fill done
- jge pf_done
-
- xor ebx,ebx
- if usesteel eq yes
- mov bl,steel ; use steel texture?
- or bl,bl
- jl s pf_no_steel
- mov dl,pf_updown[ebx]
- add dl,steelc
- mov colq,dl
- inc bl
- and bl,03fh ; 16 colours, 32 positions for steel texture
- mov steel,bl
- pf_no_steel:
- endif
-
- mov bx,[lastbyte+ebp]
- add ax,xcent
- add bx,xcent
-
- mov dx,ax ; dx = x1 (pixel position)
- shr dx,2 ; dx/4 = bytes into line
- add edi,edx ; di = addr of upper-left corner
-
- mov ecx,ebx ; cx = x2 (pixel position)
- shr cx,2 ; cx/4 = bytes into line
-
- cmp dx,cx ; start and end in same band?
- jg pf_exit ; skip if fakeline fails connection
- je pf_one_band_only ; if so, then special processing
-
- mov ah,colq ; get fill color
- sub cx,dx ; cx = # bands -1
- mov si,ax ; si = plane#(x1)
- and esi,plane_bits ; if left edge is aligned then
- jz s pf_l_plane_flush ; no special processing..
-
- ; draw "left edge" of 1-3 pixels...
-
- out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
-
- mov [edi], ah ; fill in left edge pixels
-
- inc edi ; point to middle (or right) block
- dec cx ; reset cx instead of jmp pf_right
-
- pf_l_plane_flush:
- inc cx ; add in left band to middle block
-
- ; di = addr of 1st middle pixel (band) to fill
- ; cx = # of bands to fill -1
-
- pf_right:
- mov si,bx ; get xpos2
- and si,plane_bits ; get plane values
- cmp si,0003 ; plane = 3?
- je s pf_r_edge_flush ; hey, add to middle
-
- ; draw "right edge" of 1-3 pixels...
-
- out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
-
- mov esi,edi ; get addr of left edge
- add esi,ecx ; add width-1 (bands)
- dec esi ; to point to top of right edge
-
- pf_right_loop:
- mov [esi], ah ; fill in right edge pixels
-
- dec cx ; minus 1 for middle bands
- jz s pf_exit ; uh.. no middle bands...
-
- pf_r_edge_flush:
-
- ; di = addr of upper left block to fill
- ; cx = # of bands to fill in (width)
-
- out_8 sc_data, all_planes ; write to all planes
-
- mov dx, xactual/4 ; dx = di increment
- sub dx, cx ; = screen_width-# planes filled
-
- mov al, ah ; colour is in high and low for stosw
-
- pf_middle_loop:
- shr cx,1 ; use doubleword transfer
- jnc s pf_ord
- stosb ; if cx odd, store byte first
- pf_ord:
- rep stosw ; don't use stosd
- pf_exit:
- pop edi
- mov [firstbyte+ebp],1000 ; reset table for next polygon
- mov [lastbyte+ebp],-1000
- add bp,2
- add edi,xactual/4
- jmp pf_more_lines
-
- pf_one_band_only:
- cmp ax, cliplt
- jne s pf_nexit
- cmp bx,ax
- je s pf_exit
- pf_nexit:
- cmp ax, cliprt
- je s pf_exit
- mov si,ax ; get left clip mask, save x1
- and esi,plane_bits ; mask out row #
- mov al,left_clip_mask[esi] ; get left edge mask
- mov si,bx ; get right clip mask, save x2
- and si,plane_bits ; mask out row #
- and al,right_clip_mask[esi] ; get right edge mask byte
-
- out_8 sc_data, al ; clip for left & right masks
-
- mov ah,colq ; get fill color
- mov [edi], ah ; fill in pixels
- jmp s pf_exit ; outa here, for this line
-
- ; small steel texture, make sure to set shl bl,*1* before skip_steel:
-
- ;pf_updown db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- ; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
- ; db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- ; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
-
- ; large steel texture, make sure to set shl bl,*2* before skip_steel:
-
- pf_updown db 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9
- db 10,10,11,11,12,12,13,13,14,14,15,15
- db 15,15,14,14,13,13,12,12,11,11,10,10
- db 9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0
-
- fastimultable label word
- i=0
- rept yactual
- dw i*(xactual/4)
- i=i+1
- endm
-
- resetupd: ; make old update equal current update
- if useborders eq yes
-
- mov ax,xupdate[0] ; and reset current update
- mov lxupdate[0],ax
- mov ax,xupdate[2]
- mov lxupdate[2],ax
- mov ax,yupdate[0]
- mov lyupdate[0],ax
- mov ax,yupdate[2]
- mov lyupdate[2],ax
- mov ax,xmaxs
- mov bx,xmins1
- mov cx,ymaxs
- mov dx,ymins1
- mov xupdate[0],ax
- mov xupdate[2],bx
- mov yupdate[0],cx
- mov yupdate[2],dx
-
- endif
-
- ret
-
- ; hey! where is my postcard! see readme.doc file and send me that postcard!
-
- initpages:
- pushw 0
- call set_display_page
-
- pushw 0
- call set_active_page
- pushw 0
- call clear_vga_screen
-
- pushw 1
- call set_active_page
- pushw 0
- call clear_vga_screen
-
- ret
-
- flip_page:
- if not pages eq 1
-
- mov ax,display_page
- xor al,1
- push ax
- call set_display_page
-
- mov ax,active_page
- xor al,1
- push ax
- call set_active_page
-
- else
-
- call sync_display
-
- display "Note: Page flipping not allowed with only 1 page"
- display " See equ.inc to select a mode with more than 1 page"
-
- endif
-
- ret
-
- ; draw a line in tables firstbyte,lastbyte
- ;
- ; line is not drawn on screen but is drawn in memory tables. to use,
- ; tables must be clear, (default is always clear), just draw
- ; line around screen, in any order, then call poly_fill. the polygon will
- ; be drawn and checked in memory, then poly_fill will plop it on the current
- ; page. poly_fill routine clears tables during plot so tables are ready for
- ; more lines and more polygons.
-
- align 16
-
- fakeline:
- mov ax,y1
- cmp y2,ax ; flip order of points if drawing up
- jg s okorder
- mov bx,x1
- xchg bx,x2
- xchg bx,x1
- xchg ax,y2
- mov y1,ax
- okorder:
- cmp ax,oney
- jge s nonewoney
- mov oney,ax
- nonewoney:
- if useborders eq yes
-
- cmp ax,yupdate+0 ; update borders for clearing routine
- jge s up_no1
- mov yupdate+0,ax
- up_no1:
- mov ax,y2
- cmp ax,yupdate+2
- jng s up_no2
- mov yupdate+2,ax
- up_no2:
- mov dx,xupdate+0
- mov cx,xupdate+2
- mov ax,x1
- mov bx,x2
-
- cmp ax,dx
- jge s up_no3
- dec ax
- mov xupdate+0,ax
- mov dx,ax
- inc ax
- up_no3:
- cmp bx,cx
- jle s up_no4
- inc bx
- mov xupdate+2,bx
- mov cx,bx
- dec bx
- up_no4:
- cmp bx,dx
- jge s up_no5
- dec bx
- mov xupdate+0,bx
- up_no5:
- cmp ax,cx
- jle s up_no6
- inc ax
- mov xupdate+2,ax
- up_no6:
- endif
-
- mov ax,x2 ; ax=x
- sub ax,x1
- mov bx,y2 ; bx=y
- sub bx,y1
- jle sliver
-
- mov rise,bx
- movsx ebx,bx
-
- shl eax,16
- cdq
- idiv ebx
- mov ebp,eax ; ebp = slope*65536 (allows decimals)
-
- mov ax,ymins
- cmp y1,ax ; check if above screen
- jge s li_abov1
- sub ax,y1 ; ax = abs(difference of ymin-y1)
- sub rise,ax ; dec counter
- jle li_out ; line totally off screen
-
- movsx eax,ax ; prepare for 32bit mul
- imul ebp
- shr eax,16 ; get top word
- add x1,ax ; set new x1,y1 pair
- mov ax,ymins
- mov y1,ax
- li_abov1:
- movsx edx,x1
- shl edx,16
- mov cx,rise
- mov ax,y1
- movzx ebx,ax ; bx pointer first/lastbyte table
- sub bx,ymins
- shl bx,1 ; bx now word
-
- add ax,cx ; will line go off bottom of screen?
- cmp ax,ymaxs
- jl s linep ; no...
- sub ax,ymaxs ; yes, truncate cx for early exit
- sub cx,ax
- jle s li_out ; right off screen
- linep:
- mov eax,edx
- movzx ecx,cx
-
- mov di,xmins
- mov si,xmaxs1
-
- align 16
- lineloop:
- shr edx,16 ; main line drawing loop!!!
-
- cmp dx,di
- jg s nou
- mov dx,di
- nou:
- cmp dx,si
- jl s noq
- mov dx,si
- noq:
- cmp dx,firstbyte[ebx] ; fix first and lastbyte table
- jge s ci1
- mov firstbyte[ebx],dx
- ci1:
- cmp dx,lastbyte[ebx]
- jng s ci2
- mov lastbyte[ebx],dx
- ci2:
- add eax,ebp
- mov edx,eax
- add bx,2
- loop s lineloop
- li_out:
- ret
- align 16
- sliver:
- movzx ebx,y1 ; bx pointer first/lastbyte table
-
- cmp bx,ymaxs
- jge li_out
- cmp bx,ymins ; clip to borders
- jl li_out
-
- sub bx,ymins
- shl ebx,1 ; ebx now word
-
- mov cx,x1
- cmp cx,xmins
- jge s nouq1
- mov cx,xmins
- nouq1:
- cmp cx,xmaxs
- jl s noqq1
- mov cx,xmaxs1
- noqq1:
- cmp cx,firstbyte[ebx] ; fix first and lastbyte table
- jg s ci1q1
- mov firstbyte[ebx],cx
- ci1q1:
- cmp cx,lastbyte[ebx]
- jng s ci6q1
- mov lastbyte[ebx],cx
- ci6q1:
- mov cx,x2
- cmp cx,xmins
- jge s nouq2
- mov cx,xmins
- nouq2:
- cmp cx,xmaxs
- jl s noqq2
- mov cx,xmaxs1
- noqq2:
- cmp cx,firstbyte[ebx] ; fix first and lastbyte table
- jg s ci1q2
- mov firstbyte[ebx],cx
- ci1q2:
- cmp cx,lastbyte[ebx]
- jng s ci6q
- mov lastbyte[ebx],cx
- ci6q:
- ret
-
- db " ---- Hey, What are you doing ripping my code?! ---- "
-
- ; set new clipping parameters where center is in middle of points ax,bx cx,dx
- ; where points are absolutes! eg (10,10) (50,50) would be a small window in
- ; the top corner of the screen.
-
- set_clip_absolute:
-
- mov si,cx ; calc center based on points
- sub si,ax
- shr si,1
- add si,ax
-
- mov di,dx
- sub di,bx
- shr di,1
- add di,bx
-
- sub ax,si ; now make points offset from center
- sub cx,si
- sub bx,di
- sub dx,di
-
- ; set new clipping parameters. does all pre-calculation for variables and
- ; resets oney, firstbyte and lastbyte table. si,di is center of screen. ax,bx
- ; and cx,dx are topleft and botright points to clip to. clipping will include
- ; minimum clip variables but will exclude maximum clip variables. eg -160,-100
- ; +160,+100, with center 160,100 are valid clip parameters. points are offsets
- ; from center, not absolutes! this allows you to have the camera looking to the
- ; left or right of where the pilot/plane is moving without having to change
- ; the camera angle. note: this can only change slightly as distortion occures
- ; with too large an offset. make sure to assemble the original file with the
- ; maximum y size you will ever need so tables are set to correct size.
-
- set_clip_offset:
- mov bp,dx
- sub bp,bx
- cmp bp,ymax-ymin ; check input parameters with assembley restraints
- jg you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this
-
- mov xmins,ax
- mov xmaxs,cx
- mov ymins,bx
- mov ymaxs,dx
- mov xcent,si
- mov ycent,di
-
- mov cliptp,di
- add cliptp,bx
-
- mov ycentp1,di
- inc ycentp1
-
- mov ycents1,di
- dec ycents1
-
- mov clipbt,di
- add clipbt,dx
- dec clipbt
-
- mov cliplt,si
- add cliplt,ax
-
- mov cliprt,si
- add cliprt,cx
- dec cliprt
-
- mov xmaxxcent,si
- add xmaxxcent,cx
-
- mov ymaxycent,di
- add ymaxycent,dx
-
- mov xmins1,ax
- dec xmins1
-
- mov xmaxs1,cx
- dec xmaxs1
-
- mov ymins1,bx
- dec ymins1
-
- mov ymaxs1,dx
- dec ymaxs1
-
- movsx eax,ax
- movsx ebx,bx
- movsx ecx,cx
- movsx edx,dx
-
- mov xmit,eax
- mov xmat,ecx
- mov ymit,ebx
- mov ymat,edx
-
- sub xmit,tolerance
- add xmat,tolerance
- sub ymit,tolerance
- add ymat,tolerance
- you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this:
- ret
-
- align 16
-
- ; update vector list based on traces_past
- ; i could have used a loop but shl ax,cl works faster
- ;
- ; what i am really doing is:
- ;
- ; for i = 1 to traces_past
- ; call updvectors
- ; next i
- ;
- ; but instead i am shifting and adding (if bit present) for a faster method
- ; you get the idea right?
- ;
- ; this way, the slower the machine, the faster we move the objects to
- ; maintain a universal speed from 486dx66 machine to 386sx25 machine
-
- updvectors:
- mov bx, traces_past
- mov bp,bx
- mov traces_past,0
-
- mov dx,1
- xor cl,cl
- up_loop:
- shr bl,1
- jnc not_call
- call updvectors2
- not_call:
- shl dx,1 ; dx = 1,2,4,8..
- add cl,1 ; cx = 0,1,2,3,4,5,6...
- or bl,bl ; all bits clear?
- jne up_loop
-
- cmp wfollow,no ; check if camera has reached follow object
- je s nretest ; nothing to follow
- cmp eyeacount,0
- jne s nretest ; not reached yet
- mov si,wfollow ; looking at it, re-call newfollow
- mov di,oldspeed
- cmp di,bp
- ja newfollow ; re-calculate in case its accelerating
-
- jmp just_look_at_it_now_instead_of_calculating
- nretest:
- ret
-
- align 16
-
- updvectors2: ; update vector list - shifted by cl
- ; and dec'ed by dx
- i=0
- rept maxobjects+1 ; generate unrolled update loop
- local nupang, nuploc, nuder, nuuder
-
- cmp acount+i*2,0
- je nupang
- sub acount+i*2,dx
- ja nuder
-
- mov acount+i*2,0 ; counter has expired with decimals!, now
- mov ax,vxsfinal+i*2 ; use final position!
- mov vxs+i*2,ax
- mov ax,vysfinal+i*2
- mov vys+i*2,ax
- mov ax,vzsfinal+i*2
- mov vzs+i*2,ax
- jmp nupang ; outa here
- align 16
- nuuder:
- mov lcount+i*2,0
- mov eax,xsfinal+i*4 ; linear counter has expired with carry!
- mov xs+i*4,eax
- mov eax,ysfinal+i*4
- mov ys+i*4,eax
- mov eax,zsfinal+i*4
- mov zs+i*4,eax
- jmp nuploc
- align 16
- nuder:
- mov ax,vxadds+i*2 ; update angles
- shl ax,cl
- add ax,vxs+i*2
- mov vxs+i*2,ax
-
- mov ax,vyadds+i*2
- shl ax,cl
- add ax,vys+i*2
- mov vys+i*2,ax
-
- mov ax,vzadds+i*2
- shl ax,cl
- add ax,vzs+i*2
- mov vzs+i*2,ax
- nupang:
- cmp lcount+i*2,0
- je nuploc
- sub lcount+i*2,dx
- jna nuuder ; go backward to avoid instruction buffer flush
- mov eax,xadds+i*4 ; update position
- shl eax,cl
- add eax,xs+i*4
- mov xs+i*4,eax
-
- mov eax,yadds+i*4
- shl eax,cl
- add eax,ys+i*4
- mov ys+i*4,eax
-
- mov eax,zadds+i*4
- shl eax,cl
- add eax,zs+i*4
- mov zs+i*4,eax
- nuploc:
- i=i+1
- endm
-
- ret
-
- align 16
-
- put_object:
- movzx esi,si
- mov xs[esi*4],ebx
- mov ys[esi*4],ecx
- mov zs[esi*4],ebp
- ret
-
- align 16
-
- set_angle:
- movzx esi,si
- mov vxs[esi*2],bx
- mov vys[esi*2],cx
- mov vzs[esi*2],bp
- ret
-
- align 16
- set_shape:
- movzx esi,si
- mov whatshape[esi*2],ax
- ret
-
- align 16
-
- set_object_on:
- movzx esi,si
- mov onoff[esi],1
- ret
-
- align 16
-
- set_object_off:
- movzx esi,si
- mov onoff[esi],0
- ret
-
- ; move object si from wherever it is now to ebx,ecx,ebp in di frames
- ; move is 32 bit, make sure high words of registers are set!
- ; time to get there is 16 bit. (if you need more, think! 65535 frames at
- ; 1/30 frames a sec is 36 minutes!)
-
- align 16
-
- move_si:
- movzx esi,si
- shl si,2 ; si = dword
-
- mov xsfinal[esi],ebx
- mov ysfinal[esi],ecx
- mov zsfinal[esi],ebp
-
- sub ebx,xs[esi]
- sub ecx,ys[esi]
- sub ebp,zs[esi]
-
- movzx edi,di
-
- mov eax,ebx ; 32 bit moves
-
- cdq
- idiv edi
- mov xadds[esi],eax
-
- mov eax,ecx
- cdq
- idiv edi
- mov yadds[esi],eax
-
- mov eax,ebp
- cdq
- idiv edi
- mov zadds[esi],eax
-
- shr si,1 ; si = word
-
- mov lcount[esi],di
- shr si,1 ; restore original si
-
- ret
-
- align 16
-
- ; rotate object si from wherever it is now to ebx,ecx,ebp in di frames
- ; rotate is 32 bit, make sure high words of registers are set!
- ; time to get there is 16 bit. note: although resulting angle will be
- ; 16 bit, input angle is 32 bit!. this allows you to rotate many times
- ; before coming to rest at a specified angle and also allows you to
- ; specify the direction of rotation. di specifies time to arrive.
- ; final location is absolute, not relative to current angle.
-
- ; eg 00000100 is "rotate forwards until 100 degrees"
- ; 00078000 is "rotate 7 full rotations and come to rest at 32768 degrees"
- ; fffd9000 is "rotate backwards 2 rotations and come to rest at 9000h degrees"
- ; fffffff0 is "rotate backwards until 65520 degrees (-16)"
-
- ; therefore, to reverse the direction of rotation (but maintain the final
- ; position) xor ebx,0ffff0000h (or ecx or ebp). ax is final position, but
- ; top word of eax determines direction and number of turn to get there.
-
- twist_si:
- movzx esi,si
- shl si,1 ; si = word
-
- mov vxsfinal[esi],bx ; set final position when acount becomes 0
- mov vysfinal[esi],cx
- mov vzsfinal[esi],bp
-
- movzx eax,vxs[esi]
- sub ebx,eax
- movzx eax,vys[esi]
- sub ecx,eax
- movzx eax,vzs[esi]
- sub ebp,eax
-
- movzx edi,di
-
- mov eax,ebx ; 32 bit rotate
- cdq
- idiv edi
- mov vxadds[esi],ax
-
- mov eax,ecx
- cdq
- idiv edi
- mov vyadds[esi],ax
-
- mov eax,ebp
- cdq
- idiv edi
- mov vzadds[esi],ax
-
- mov acount[esi],di
- shr si,1 ; restore original si
-
- ret
-
- align 16
-
- look_at_it: ; force camera to look at object wherelook
- mov si,wherelook
- cmp si,no
- je s noat ; get out, no object to look at (-1=flag)
-
- mov edi,cameraobject
- movzx esi,si
- call calc_angles ; calculate difference between camera and obj
- mov eyeay,bx ; this is where the camera should look...
- mov eyeax,ax
- noat:
- ret
-
- ; calculate angles between objects esi and edi. angles are from point of view
- ; of di.
-
- align 16
-
- calc_angles:
- call get_displacement
-
- calc_middle:
- push ecx ebx ebp
-
- mov ecx,ebx ; first get z,x plane, (y angle)
- mov eax,ebp
-
- or eax,eax
- je lk_right_above ; check arctan(cx/0)
-
- call arctan
- lk_resume:
- mov dsq,ax ; save y angle
- call cosign ; set up 32bit sin/cos multipliers
- mov vycos,eax
- mov ax,dsq
- call sign
-
- pop ebp ebx ; now compute sqr(z^2+x^2) through y rotation
-
- imul ebx ; use angle from calculation above
- shrd eax,edx,14
- mov edi,eax
- mov eax,vycos
- imul ebp
- shrd eax,edx,14
- add eax,edi ; di = new z = run
-
- pop ecx ; cx = rise
- or eax,eax
- je s noaq
-
- call arctan ; get ax=arctan(y/sqr(z^2+x^2))
-
- mov bx,dsq ; bx = y angle , ax = x angle
- noaq:
- ret
-
- align 16
-
- lk_right_above:
- mov ax,vys[esi] ; camera directly above object, use old y
- jmp lk_resume
-
- align 16
-
- get_displacement:
- movzx esi,si ; in case user is lazy
- movzx edi,di
-
- mov ebx,xs[esi*4] ; get displacement of esi to edi
- sub ebx,xs[edi*4]
- mov ecx,ys[esi*4]
- sub ecx,ys[edi*4]
- mov ebp,zs[esi*4]
- sub ebp,zs[edi*4]
- ret
-
- align 16
-
- ; new follow, si = object for new follow, di = time to get there.
-
- newfollow:
- mov wfollow,si ; save in case object is accelerating
- mov oldspeed,di
- mov wherelook,no ; disable look_at_si routine
-
- call where_si ; figure out where object si will end up
-
- mov di,oldspeed ; figure out where camera will end up
- mov ax,eyelcount
- cmp ax,di ; if di>lcount, shorten to lcount
- ja s tx
- mov di,ax
- tx:
- movzx edi,di
-
- mov eax,eyexadds
- imul edi ; figure out where camera will be di*frames
- add eax,eyex
- sub ebx,eax ; get displacement to eye
-
- mov eax,eyeyadds
- imul edi
- add eax,eyey
- sub ecx,eax
-
- mov eax,eyezadds
- imul edi
- add eax,eyez
- sub ebp,eax
-
- call calc_middle ; jump in middle of angle computation
-
- mov eyefinalax,ax
- mov eyefinalay,bx
-
- mov di,bx
-
- sub ax,eyeax ; get difference from where we are now
- sub di,eyeay
-
- add ax,followtol ; check if already looking at it
- cmp ax,followtol*2
- ja s calcit
-
- add di,followtol
- cmp di,followtol*2
- jb just_look_at_it_now_instead_of_calculating
- sub di,followtol
- calcit:
- sub ax,followtol
-
- mov si,oldspeed ; ax=x angle, di=y angle, si=# frames
- cwd
- push dx ; save sign extend
- idiv si ; x/time
- pop dx
- or ax,ax
- jne s n0
- shl dx,1
- mov ax,dx
- inc ax ; ax = 1 or ax = -1
- n0:
- mov eyevxadds,ax
-
- mov ax,di
- cwd
- push dx
- idiv si ; y/time
- pop dx
- or ax,ax ; check if zero slope, must have some...
- jne s n1
- shl dx,1 ; dx = fffe (-2) or 0
- mov ax,dx
- inc ax ; ax = 1 or ax = -1
- n1:
- mov eyevyadds,ax
-
- mov eyeacount,si
- shr oldspeed,1 ; if need to try again, time/2
-
- mov ax,eyevzadds ; now adjust any z rotation into finalz
- imul si
- add ax,eyeaz
- mov eyefinalaz,ax
-
- ret
-
- align 16
-
- just_look_at_it_now_instead_of_calculating:
- mov ax,wfollow
- mov wherelook,ax ; already looking at object, now follow it
- mov wfollow,no
- ret
-
- align 16
-
- ; figure out where object si will be in di frames.
-
- where_si:
- movzx esi,si
-
- mov ax,lcount[esi*2]
- or ax,ax
- jne s nx
-
- mov ebx,xs[esi*4] ; if object has no velocity, xs is position
- mov ecx,ys[esi*4]
- mov ebp,zs[esi*4]
- ret
- nx:
- cmp ax,di ; if di>lcount, shorten to lcount
- ja s nxq
- mov di,ax
- nxq:
- movzx edi,di
-
- mov eax,xadds[esi*4] ; figure out where object will be di*frames
- imul edi
- add eax,xs[esi*4]
- mov ebx,eax
-
- mov eax,yadds[esi*4]
- imul edi
- add eax,ys[esi*4]
- mov ecx,eax
-
- mov eax,zadds[esi*4]
- imul edi
- add eax,zs[esi*4]
- mov ebp,eax
-
- ret
-
- align 16
-
- ; draw vectors from sides list.
- ; number of "sides" is "showing"
-
- dv_none2:
- ret
- drawvect:
- cmp showing,0 ; no sides visible?
- je s dv_none2
-
- mov whichside,0 ; start at side 0
- movzx ebp,order[0] ; indexer to sides
- dv_loop2:
- test textures[ebp],line+himap+point ; test if line, point, scalable bitmap or bitmapped texture
- jnz dv_testit ; yes, do faster line routine
-
- shl bp,mult
- mov dx,sides[ebp] ; first point is end flag
- dv_loop1:
- movzx esi,sides[ebp] ; get point, shl 1 not needed, pre-shl'ed
- mov ax,[xp+esi]
- mov bx,[yp+esi]
- mov x1,ax
- mov y1,bx
-
- mov si,[sides+ebp+2] ; get next point
-
- cmp si,dx ; test if last = first, therefore done
- pushf
-
- mov ax,[xp+esi]
- mov bx,[yp+esi]
-
- mov x2,ax
- mov y2,bx
-
- push ebp dx
- call fakeline ; draw next line
- pop dx ebp
-
- add bp,2 ; bump to next pointer now
- popf ; was this point equal to the first point?
- jne s dv_loop1 ; no, draw more lines
-
- movzx esi,whichside ; set colour for this side
- mov si,order[esi]
- mov ebx,palxref ; get offset of palette cross reference table for this object
- mov al,b surfcolors[esi]
- xlat
- mov colq,al
-
- mov bx,textures[esi] ; use register which we can access low byte
- and bl,wavey ; strip steel command bit
- sub bl,wavey
- mov steel,bl
-
- call poly_fill
-
- dv_return:
- add whichside,2 ; bump bp to next block of points
- movzx ebp,whichside
- mov bp,order[ebp] ; get sort order
- dec showing ; count for all sides
- jne dv_loop2
- dv_none:
- ret
-
- align 16
- dv_testit:
- mov ax,textures[ebp] ; perform command, return to dv_return
- test al,line
- jnz dv_doline
- test al,point
- jnz dv_dopoint
-
- ; draw bitmap at location x,y,z if userotate = 32 or command = 32
-
- shl bp,mult
- push ax ebp
-
- movzx ebx,[sides+4+ebp]
- movzx ecx,[sides+6+ebp]
-
- movzx esi,[sides+2+ebp]
- shl si,2 ; si = dword
- add ebx,bitx[esi]
- add ecx,bity[esi] ; ebx,ecx = top corner of bitmap in 3d
-
- mov eax,bitbase[esi]
- mov bitmap,eax
-
- mov si,[sides+0+ebp]
- mov bp,[zp+esi]
-
- call make3d ; ebx,ecx = difference from center
-
- pop ebp
-
- movzx esi,[sides+0+ebp] ; get point
- mov ax,[xp+esi]
- mov bp,[yp+esi]
-
- sub ax,bx ; bx = x width/2 ax, bp = top corner
- sub bp,cx ; cx = y height/2
-
- if useborders eq yes
-
- cmp bp,yupdate+0
- jge s up_nq12
- mov yupdate+0,bp
- up_nq12:
- cmp ax,xupdate+0
- jge s up_nq32
- mov xupdate+0,ax
- up_nq32:
- mov di,ax
- mov dx,bp
-
- endif
-
- add ax,xcent
- add bp,ycent
- mov destx,ax
- mov desty,bp
-
- shl bx,1
- shl cx,1
-
- mov destwidth,bx
- mov destheight,cx
-
- if useborders eq yes
- add di,bx
- add dx,cx
-
- cmp dx,yupdate+2
- jng s up_nq42
- mov yupdate+2,dx
- up_nq42:
- cmp di,xupdate+2
- jng s up_nq22
- mov xupdate+2,di
- up_nq22:
- endif
-
- pop ax
- test al,lomap-himap ; test to use 1/4 scale bitmap or full scale
- jz s noq19
-
- call xscale4
- jmp dv_return
-
- align 16
- noq19:
- call xscale2
- noq7:
- jmp dv_return
-
- align 16
-
- dv_dopoint:
- mov dx,surfcolors[ebp] ; get colour of point
-
- shl bp,mult
- movzx esi,[sides+ebp] ; get point x,y
- mov bx,[xp+esi]
- mov cx,[yp+esi]
-
- cmp bx,xmins ; check if on screen
- jl s noq7
- cmp bx,xmaxs
- jge s noq7
- cmp cx,ymins
- jl s noq7
- cmp cx,ymaxs ; ymaxs1 if larger pixel
- jge s noq7
-
- mov edi, current_page ; point to active vga page
-
- if useborders eq yes
-
- cmp cx,yupdate+0
- jge s up_no16
- mov yupdate+0,cx
- up_no16:
- cmp bx,xupdate+0
- jge s up_no36
- mov xupdate+0,bx
- up_no36:
- cmp cx,yupdate+2
- jng s up_no46
- mov yupdate+2,cx
- up_no46:
- cmp bx,xupdate+2
- jng s up_no26
- mov xupdate+2,bx
- up_no26:
- endif
-
- add bx,xcent
- add cx,ycent
-
- mov bp,dx ; save colour
-
- mov si,cx
- mov ax,[esi*2+fastimultable] ; get offset to start of line
-
- mov cx, bx ; copy to extract plane # from
- shr bx, 2 ; x offset (bytes) = xpos/4
- add bx, ax ; offset = width*ypos + xpos/4
-
- mov ax, map_mask_plane1 ; map mask & plane select register
- and cl, plane_bits ; get plane bits
- shl ah, cl ; get plane select value
- out_16 sc_index, ax ; select plane
-
- movzx ebx,bx
- mov ax,bp ; re-get colour
- mov [edi+ebx],al ; draw pixel, low is top, high is bottom
- ; add edi,xactual/4
- ; mov [edi+ebx],ah ; draw larger bullet/pixel (high byte)
-
- ; if drawing larger pixel, change above code to this!
- ; cmp cx,ymaxs1
- ; jge s noa7
-
- jmp dv_return
-
- align 16
-
- ; handle line command from drawvect, uses clipped_line routine
-
- dv_doline:
- mov edi,ebp ; save...
-
- mov ebx,palxref ; get offset of palette cross reference table for this object
- movzx ecx,b surfcolors[ebp]
- movzx bp,b [ecx+ebx]
-
- shl di,mult
- movzx esi,[sides+edi] ; get first point
- mov dx,[xp+esi]
- mov cx,[yp+esi]
-
- mov si,[sides+edi+2] ; second point indexer
-
- mov ax,[xp+esi] ; now load up second point
- mov bx,[yp+esi]
-
- call clipped_line
- jmp dv_return ; return to drawvect
-
- ; draw clipped line in cartesian format (0,0 is screen center)
- ; similar routine to fakeline but faster, more accurate and draws directly
- ; to screen (current_page). updates clearing borders (if used)
- ;
- ; draws line from (dx,cx) to (ax,bx) using colour bp
- ;
- clipped_line:
- cmp bx,cx ; flip order of points if drawing up
- jg s r_okorder
- xchg bx,cx
- xchg ax,dx
- r_okorder:
- mov x1,dx
- mov y1,cx
- mov x2,ax
- mov y2,bx
-
- if useborders eq yes
-
- cmp cx,yupdate+0 ; update borders for clearing routine
- jg s r_up_no1
- mov yupdate+0,cx
- r_up_no1:
- cmp bx,yupdate+2
- jng s r_up_no2
- mov yupdate+2,bx
- r_up_no2:
- mov bx,ax
- mov ax,dx
- mov dx,xupdate+0
- mov cx,xupdate+2
-
- cmp ax,dx
- jge s r_up_no3
- dec ax
- mov xupdate+0,ax
- mov dx,ax
- inc ax
- r_up_no3:
- cmp bx,cx
- jle s r_up_no4
- inc bx
- mov xupdate+2,bx
- mov cx,bx
- dec bx
- r_up_no4:
- cmp bx,dx
- jge s r_up_no5
- dec bx
- mov xupdate+0,bx
- r_up_no5:
- cmp ax,cx
- jle s r_up_no6
- inc ax
- mov xupdate+2,ax
- r_up_no6:
- mov ax,x2 ; ax=x
- sub ax,x1
- mov bx,y2 ; bx=y
- sub bx,y1
-
- elseif not useborders eq yes
-
- sub ax,dx
- sub bx,cx
-
- endif
-
- mov dx,bp
- mov colq,dl
-
- mov dx,ymaxs
- cmp y1,dx
- jge cl_return
-
- mov rise,bx
- movsx ebx,bx
- or ebx,ebx
- jne s r_nsliver
-
- mov bx, y1
- cmp bx, ymins ; draw sliver, avoid divide by zero
- jl cl_return
- cmp bx, dx ; dx = ymax
- jge cl_return
-
- add bx,ycent
- movzx esi,bx
- movzx eax,[esi*2+fastimultable] ; get offset to start of line
- mov edi, current_page
- add edi, eax ; edi = starting y location
-
- mov rise,1
-
- mov dx, x1 ; from here...
- mov si, x2 ; ..to here
-
- cmp si,xmins
- jge s u_nou3
- mov si,xmins
- u_nou3:
- cmp si,xmaxs
- jl s u_noq3
- mov si,xmaxs1
- u_noq3:
- jmp r_splint ; re-enter draw later in code
-
- align 16
- r_nsliver:
- shl eax,16
- cdq
- idiv ebx
- mov ebp,eax ; ebp = slope*65536 (allows decimals)
-
- mov ax,ymins
- cmp y1,ax ; check if above screen
- jge s r_li_abov1
- sub ax,y1 ; ax = abs(difference of ymin-y1)
- sub rise,ax ; dec counter
- jle cl_return ; line totally off screen
-
- movsx eax,ax ; prepare for 32bit mul
- imul ebp
- shr eax,16 ; get top word
- add x1,ax ; set new x1,y1 pair
- mov ax,ymins
- mov y1,ax
-
- r_li_abov1:
- mov bx,y1 ; bx distance from top of screen
- add bx,ycent
- movzx esi,bx ; calculate screen address
- movzx eax,[esi*2+fastimultable] ; get offset to start of line
- mov edi, current_page
- add edi,eax ; edi = starting y location
-
- movsx edx,x1
- shl edx,16
- mov cx,rise
- mov ax,y1
- add ax,cx ; will line go off bottom of screen?
- cmp ax,ymaxs
- jl s r_linep ; no...
- sub ax,ymaxs ; yes, truncate cx for early exit
- sub rise,ax
- jle cl_return
- r_linep:
- mov eax,edx
- movzx ecx,cx
-
- mov esi,edx
- shr esi,16
-
- cmp si,xmins
- jge s r_nou
- mov si,xmins
- r_nou:
- cmp si,xmaxs
- jl s r_noq
- mov si,xmaxs1
-
- align 16
- r_noq:
-
- r_lineloop:
- add eax,ebp ; main line drawing loop!!! (for lines)
- mov edx,eax
- shr edx,16
- r_splint:
- cmp dx,xmins
- jge s u_nou
- mov dx,xmins
- cmp dx,si
- je r_mis
- u_nou:
- cmp dx,xmaxs
- jl s u_noq
- mov dx,xmaxs1
- cmp dx,si
- je r_mis
- u_noq:
- push dx edi ebp eax ; save for next line
- cmp dx,si
- jle s r_no_switch
- xchg dx,si
- r_no_switch:
-
- add dx,xcent
- add si,xcent
-
- mov ax,dx
- mov bx,si
- mov x2,si
-
- shr dx,2 ; dx/4 = bytes into line
- movzx edx,dx
- add edi,edx ; di = addr of upper-left corner
-
- movzx ecx,bx ; cx = x2 (pixel position)
- shr cx,2 ; cx/4 = bytes into line
-
- cmp dx,cx ; start and end in same band?
- je rf_one_band_only ; if so, then special processing
-
- sub cx,dx ; cx = # bands -1
- movzx esi,ax ; si = plane#(x1)
- and si,plane_bits ; if left edge is aligned then
- jz s rf_l_plane_flush ; no special processing..
-
- ; draw "left edge" of 1-3 pixels...
-
- out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
-
- mov al,colq ; get fill color
- mov [edi], al ; fill in left edge pixels
-
- inc edi ; point to middle (or right) block
- dec cx ; reset cx instead of jmp s rf_right
-
- rf_l_plane_flush:
- inc cx ; add in left band to middle block
-
- ; di = addr of 1st middle pixel (band) to fill
- ; cx = # of bands to fill -1
-
- rf_right:
- movzx esi,bx ; get xpos2
- and si,plane_bits ; get plane values
- cmp si,0003 ; plane = 3?
- je s rf_r_edge_flush ; hey, add to middle
-
- ; draw "right edge" of 1-3 pixels...
-
- out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
-
- mov esi,edi ; get addr of left edge
- add esi,ecx ; add width-1 (bands)
- dec esi ; to point to top of right edge
-
- mov al,colq ; get fill color
-
- rf_right_loop:
- mov [esi], al ; fill in right edge pixels
-
- dec cx ; minus 1 for middle bands
- jz s rf_exit ; uh.. no middle bands...
-
- rf_r_edge_flush:
-
- ; di = addr of upper left block to fill
- ; cx = # of bands to fill in (width)
-
- out_8 sc_data, all_planes ; write to all planes
-
- mov dx, xactual/4 ; dx = di increment
- sub dx, cx ; = screen_width-# planes filled
-
- mov al, colq ; get fill color
- mov ah, al ; colour is in high and low for stosw
- push ax ; make colour 32 bit
- shl eax,16
- pop ax
-
- rf_middle_loop:
- shr cx,1 ; use doubleword transfer
- jnc s rf_ord
- stosb ; if cx odd, store byte first
- jcxz s rf_exit ; no words after stosb
- rf_ord:
- shr cx,1
- jnc rf_dord
- stosw
- jcxz s rf_exit ; no doublewords after stosw
- rf_dord:
- rep stosd ; fill in entire line
-
- jmp s rf_exit ; outa here, for this line
-
- rf_one_band_only:
- movzx esi,ax ; get left clip mask, save x1
- and si,plane_bits ; mask out row #
- mov al,left_clip_mask[esi] ; get left edge mask
- mov si,bx ; get right clip mask, save x2
- and si,plane_bits ; mask out row #
- and al,right_clip_mask[esi] ; get right edge mask byte
-
- out_8 sc_data, al ; clip for left & right masks
-
- mov al, colq ; get fill color
- mov [edi], al ; fill in pixels
- rf_exit:
- pop eax ebp edi si ; pop screen left address
- r_mis:
- add edi, xactual/4
- dec rise
- jg r_lineloop
-
- cl_return:
- ret
-
- ; bubble sort for sides
-
- ; sort is not perfect since many sides can use the same point.
- ; if this point is the first point in the list and therefore zeds[] uses
- ; the same point for sort, the routine may mess up when plotting at some
- ; acute angles. if you ever notice this, you are way too picky. you
- ; could fix this by adjusting the load_sides routine to search for the
- ; closest z point.
-
- align 16
-
- minusd equ offset zeds - offset order
-
- sort_list:
- movzx esi,showing
- cmp si,1 ; if only one surface, exit
- jbe qke
-
- shl si,1 ; si = word
- add esi,o order
-
- align 16
- nextcx:
- sub esi,2 ; point to last word in order[] table
-
- mov ebp,esi ; set order pointer
- mov bx,w [esi] ; get order[si]
-
- mov edi,esi
- add edi,minusd
- mov cx,w [edi] ; get zeds[si]
-
- align 16
- nextdx:
- sub edi,2
- sub ebp,2
-
- cmp cx,w [edi] ; zeds is point from side, should be max z
- jle s donothing
- xchg cx,w [edi] ; don't flip entire side, just indexers to it
- xchg bx,w [ebp]
- donothing:
- cmp ebp,o order ; check bp = 0
- jne s nextdx
-
- mov [esi + minusd],cx
- mov [esi],bx
-
- cmp esi,o order + 2
- jne s nextcx
- qke:
- ret
-
- ; routine sets the "final" variables for perfect updvectors calculations
- ; this fixes the small (and i mean small) discrepancies when the raster count
- ; does not divide evenly into the objects rotational or linear count.
- ; eg lcount =1001, raster count = 10, object should move 1001 units but gets
- ; moved 100*10 (only moves 1000 units). this makes absolutly sure that an
- ; object moved to a location in si frames will actually get to that exact
- ; position! (regardless of machine speed or raster speed or number of objects
- ; on screen or whatever!).
-
- ; call this routine after setting new anglular or linear velocities. there is
- ; no need to call this routine if you are going to set a position or location
- ; but xxxfinal must be set if you are going to change the velocities. the
- ; variables xxxfinal[] are used by updvectors to set the final position/angle
- ; of an object after the counters lcount and acount have expired. if you know
- ; the final position/angle of your object, set these yourself. but if
- ; you only want to move the object and don't care where it will end up, call
- ; this routine and the final position/angle will be calculated for you.
- ; note: xxxfinal variables will only be used if the raster count does not
- ; divide evenly into the angle/linear count.
-
- ; routine calculates for object si.
-
- set_finall:
- movzx esi,si ; do this in case user is lazy...
-
- movzx ecx,lcount[esi*2] ; final position = speed * time
-
- mov eax,xadds[esi*4] ; xsfinal = xadds * lcount + position
- imul ecx ; you get the idea right?
- add eax,xs[esi*4]
- mov xsfinal[esi*4],eax
-
- mov eax,yadds[esi*4]
- imul ecx
- add eax,ys[esi*4]
- mov ysfinal[esi*4],eax
-
- mov eax,zadds[esi*4]
- imul ecx
- add eax,zs[esi*4]
- mov zsfinal[esi*4],eax
-
- ret
-
- set_finala:
- movzx esi,si ; do this in case user is lazy...
-
- mov cx,acount[esi*2] ; final angle = angular velocity * time
-
- mov ax,vxadds[esi*2] ; vxsfinal = vxadds * acount + angle
- imul cx
- add ax,vxs[esi*2]
- mov vxsfinal[esi*2],ax
-
- mov ax,vyadds[esi*2]
- imul cx
- add ax,vys[esi*2]
- mov vysfinal[esi*2],ax
-
- mov ax,vzadds[esi*2]
- imul cx
- add ax,vzs[esi*2]
- mov vzsfinal[esi*2],ax
-
- ret
-
- align 16
-
- ; point object si at object di
-
- point_it:
- push esi edi
- xchg si,di ; xchange so user doesn't get confused
- push di
- call calc_angles
- pop di
- movzx edi,di
- mov vxs[edi*2],ax
- mov vys[edi*2],bx
- pop edi esi
-
- ret
-
- align 16
-
- ; point object si in direction it is moving
-
- point_dir:
- movzx esi,si
-
- mov ebx,xadds[esi*4]
- mov ecx,yadds[esi*4]
- mov ebp,zadds[esi*4]
-
- shl ebx,4 ; * whatever to get some decimal accuracy
- shl ecx,4
- shl ebp,4
-
- align 16
-
- ; point object si at location ebx,ecx,ebp.
-
- point_to:
- mov di,si ; xchange so user doesn't get confused
- movzx edi,di
- push edi
-
- sub ebx,xs[edi*4] ; get displacement of esi to edi
- sub ecx,ys[edi*4]
- sub ebp,zs[edi*4]
-
- call calc_middle
-
- pop esi
- mov vxs[esi*2],ax
- mov vys[esi*2],bx
-
- ret
-
- align 16
-
- ; set speed of object si to ebp*angle, then set lcount to di
- ; (move object in direction it is pointing)
-
- ;
- ; xadds= - cx * sy * ebp
- ;
- ; yadds= - sx * ebp
- ;
- ; zadds= cx * cy * ebp
-
- set_speed:
- movzx esi,si
- mov lcount[esi*2],di
-
- mov ax,vxs[esi*2]
- neg ax
- push ax
- call cosign
- mov ecx,eax ; cx = cos x
- pop ax
- call sign
-
- neg eax
- imul ebp ; set y speed
- shrd eax,edx,14
- mov yadds[esi*4],eax
-
- mov ax,vys[esi*2]
- neg ax
- push ax
- call cosign
- mov edx,eax ; dx = cos y
- pop ax
- call sign
-
- mov ebx,edx ; save because imul trashes dx
-
- imul ecx ; ax = sy * cx
- shrd eax,edx,14 ; shr eax,14 compensates for cos decimals
- imul ebp
- shrd eax,edx,14
- neg eax
- mov xadds[esi*4],eax
-
- mov eax,ebx
- imul ecx
- shrd eax,edx,14
- imul ebp
- shrd eax,edx,14
- mov zadds[esi*4],eax
-
- ret
-
- ; point object si at location ebx,ecx,ebp, in di frames (di = time)
-
- ; this could also be used for the camera, but if you are going to
- ; point the camera at an object, call newfollow instead. newfollow
- ; allows for when the object is moving - newfollow will track the
- ; object as it moves and even if it accelerates!
-
- point_time:
- push di si di si ebp ecx ebx
- call where_si ; find out where object will be in di frames
-
- pop eax
- sub ebx,eax ; get displacement of where it will be to where
- neg ebx ; it should point
-
- pop eax
- sub ecx,eax
- neg ecx
-
- pop eax
- sub ebp,eax
- neg ebp
-
- pop di si ; notice reverse order for calc_middle
-
- call calc_middle
- movzx ecx,bx
- movzx ebx,ax
-
- test bx,8000h ; test to invert for other direction
- jne no_inv1
- xor ecx,0ffff0000h ; xor goes the other way
- no_inv1:
- test cx,8000h
- jne no_inv2
- xor ecx,0ffff0000h
- no_inv2:
- pop si ; pop object number
- pop di ; pop time
- movzx esi,si
-
- mov ax,vzadds[esi*2] ; figure out z (calc_middle wont)
- imul di
- add ax,vzs[esi*2]
-
- movzx ebp,ax
- test bp,8000h
- jne no_inv3
- neg ebp
- no_inv3:
- ; add ebx,00010000h ; do this if you want more than one rotation
- ; add ecx,00020000h ; along a selected axis.
- ; add ebp,00030000h ; maybe put a ret here then call twist_si yourself
-
- jmp twist_si ; twist object to this location in di frames!
-
- nullpalette:
- i=0
- rept 256
- db i
- i=i+1
- endm
-
- set_xref_palette: ; set cross referencing palette for object si
- movzx esi,si
- mov palxref[esi*4],ebx
- ret
-